以下内容记录了基于Fabric 架构,利用docker容器创建一个简单的区块链案例,并实现第一个智能合约(链码)。详细配置可以参考fabric-sample/first-network

1.环境准备

安装以下环境,详细安装过程上网搜索相关资料:

  • git
  • nodejs
  • npm
  • golang
  • docker
  • docker-compose

配置gopath环境变量,以mac系统为例,打开~/.bash_profile 添加下面内容:

1
2
3
4
5
6
#go的安装路径
export GOROOT=/usr/local/Cellar/go/1.13.4 #go安装包安装的路径
#hyperledger相关可运行文件,所在的目录,自己可以随意设置
export GOPATH=$HOME/go
#一些其他与运行hyperledger fabric运行有关的可执行文件所在的目录
export PATH=$GOROOT/bin:$GOPATH/bin:$PATH

2.下载fabric资源

  • 下载fabric

    1
    2
    3
    4
    5
    6
    7
    # 进入文件hyperledger文件路径
    # /Users/zgq/go为GPATH
    cd /Users/zgq/go/src/github.com/hyperledger
    git clone https://github.com/hyperledger/fabric.git
    cd fabric
    git tag #查看所有版本,点击q退出
    git checkout v1.14.2 #切换到tag中你想要切换到的版本
  • 下载fabric-samples

    1
    2
    3
    4
    5
    6
    7
     
    cd cd /Users/zgq/go/src
    # 从git上克隆fabric-samples ,里面有fabric例子
    git clone https://github.com/hyperledger/fabric-samples.git
    cd fabric-samples
    git tag #查看所有版本,点击q退出
    git checkout v1.14.2 #切换到fabric相同的版本
  • 下载运行hyperledger fabric所需要的二进制文件

    1
    2
    3
    4
    5
    6
    7
    8

    # 将$GOPATH/src/github.com/hyperledger/fabric/scripts/bootstrap.sh拷贝到 fabric-samples中
    # 终端进入到 fabric-samples文件夹中
    # 修改bootstrap.sh权限
    chmod +x bootstrap.sh
    #运行bootstrap.sh
    ./bootstrap.sh
    # 系统会下载一堆docker镜像、和二进制文件。

二进制文件下载有时候会因为网络问题无法下载,可以通过这个网站手动下载。
https://nexus.hyperledger.org/content/repositories/releases/org/hyperledger/fabric/hyperledger-fabric

https://nexus.hyperledger.org/content/repositories/releases/org/hyperledger/fabric-ca/hyperledger-fabric-ca

压缩包内有 bin 和 config 两个文件夹,将 bin 和 config 文件夹复制到 fabric-samples 文件夹内。

3. 体验Fabric区块链网络

你可以通过first-network来体验fabric网络。

进入fabric-samples/first-network,执行命令:

1
2
3
4
5
6
7
8
#生成网络
./byfn.sh generate

#启动
./byfn.sh up

#停止
./byfn.sh down

具体可参考 https://hyperledger-fabric.readthedocs.io/en/latest/build_network.html

4.创建Helloworld区块链网络

4.1 架构设计

本案例部署一个排序(orderer)服务,两个组织(org1,org2)和四个节点(peer),每个组织包括两个节点, 另外每个组织一个ca(可选)。
需要五台计算机(也可以在一个主机上模拟,这里在一台mac环境搭建演示)架构配置如下:
架构


  • orderer.example.com

  • peer0.org1.example.com
  • peer1.org1.example.com
  • ca.org1.example.com

  • peer0.org2.example.com
  • peer1.org2.example.com
  • ca.org2.example.com

4.2 准备

1
2
3
4
5
6
7
8
#命令行进入到fabric-samples目录下
cd ~/go/src/fabric-samples

#新建helloworld目录
mkdir helloworld

#拷贝脚本到helloworld下方便操作
cp -r ../bin /bin

4.3 生成配置文件

配置文件主要包括证书和通道
生成后分别放在两个文件夹中:crypto-config、channel-artifacts

4.3.1 创建crypto-config.yaml

使用fabric提供的cryptogen工具生成文件模板


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
 ./bin/cryptogen showtemplate > crypto-config.yaml
 

```
修改crypto-config.yaml
,添加组织,和orderer节点。

```yaml
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

# ---------------------------------------------------------------------------
# "OrdererOrgs" - Definition of organizations managing orderer nodes
# ---------------------------------------------------------------------------
OrdererOrgs:
# ---------------------------------------------------------------------------
# Orderer
# ---------------------------------------------------------------------------
- Name: Orderer
Domain: example.com
EnableNodeOUs: true
# ---------------------------------------------------------------------------
# "Specs" - See PeerOrgs below for complete description
# ---------------------------------------------------------------------------
Specs:
- Hostname: orderer
- Hostname: orderer2
- Hostname: orderer3
- Hostname: orderer4
- Hostname: orderer5

# ---------------------------------------------------------------------------
# "PeerOrgs" - Definition of organizations managing peer nodes
# ---------------------------------------------------------------------------
PeerOrgs:
# ---------------------------------------------------------------------------
# Org1
# ---------------------------------------------------------------------------
- Name: Org1
Domain: org1.example.com
EnableNodeOUs: true
Specs:
- Hostname: peer0
- Hostname: peer1
- Hostname: peer2
- Hostname: peer3
- Hostname: peer4
# ---------------------------------------------------------------------------
# "Specs"
# ---------------------------------------------------------------------------
# Uncomment this section to enable the explicit definition of hosts in your
# configuration. Most users will want to use Template, below
#
# Specs is an array of Spec entries. Each Spec entry consists of two fields:
# - Hostname: (Required) The desired hostname, sans the domain.
# - CommonName: (Optional) Specifies the template or explicit override for
# the CN. By default, this is the template:
#
# "{{.Hostname}}.{{.Domain}}"
#
# which obtains its values from the Spec.Hostname and
# Org.Domain, respectively.
# ---------------------------------------------------------------------------
# Specs:
# - Hostname: foo # implicitly "foo.org1.example.com"
# CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above
# - Hostname: bar
# - Hostname: baz
# ---------------------------------------------------------------------------
# "Template"
# ---------------------------------------------------------------------------
# Allows for the definition of 1 or more hosts that are created sequentially
# from a template. By default, this looks like "peer%d" from 0 to Count-1.
# You may override the number of nodes (Count), the starting index (Start)
# or the template used to construct the name (Hostname).
#
# Note: Template and Specs are not mutually exclusive. You may define both
# sections and the aggregate nodes will be created for you. Take care with
# name collisions
# ---------------------------------------------------------------------------
Template:
Count: 2
# Start: 5
# Hostname: {{.Prefix}}{{.Index}} # default
# ---------------------------------------------------------------------------
# "Users"
# ---------------------------------------------------------------------------
# Count: The number of user accounts _in addition_ to Admin
# ---------------------------------------------------------------------------
Users:
Count: 1
# ---------------------------------------------------------------------------
# Org2: See "Org1" for full specification
# ---------------------------------------------------------------------------
- Name: Org2
Domain: org2.example.com
EnableNodeOUs: true
Specs:
- Hostname: peer0
- Hostname: peer1
- Hostname: peer2
- Hostname: peer3
- Hostname: peer4
Template:
Count: 2
Users:
Count: 1

4.3.2 生成证书文件

cryptogen generate –config=./crypto-config.yaml

4.3.3 生成创世区块

首先要确保channel-artifacts文件夹存在,如果不存在需要手动创建,不然会报错。

1
configtxgen -profile TwoOrgsOrdererGenesis  -outputBlock ./channel-artifacts/genesis.block

4.3.4 生成通道配置文件

其中通道名mychannel可以修改为自己的名称

1
configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/mychannel.tx -channelID mychannel

4.3.5 生成锚节点配置文件

Org1

1
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP

Org2

1
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP

所有需要的配置文件全部建立完成,在channel-artifacts中应该有以下几个文件。my
channel.tx、genesis.block、Org1MSPanchors.tx、Org2MSPanchors.tx

4.4 配置docker-compose文件

相关配置内容可参考first-network中的配置

docker-compose-orderer.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

version: '2'

networks:
hello:

services:

orderer.example.com:
container_name: orderer.example.com
image: hyperledger/fabric-orderer
environment:
- ORDERER_GENERAL_LOGLEVEL=debug
- ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
- ORDERER_GENERAL_GENESISMETHOD=file
- ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
- ORDERER_GENERAL_LOCALMSPID=OrdererMSP
- ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp
# enabled TLS
- ORDERER_GENERAL_TLS_ENABLED=true
- ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key
- ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt
- ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
- ORDERER_KAFKA_RETRY_SHORTINTERVAL=1s
- ORDERER_KAFKA_RETRY_SHORTTOTAL=30s
- ORDERER_KAFKA_VERBOSE=true
working_dir: /opt/gopath/src/github.com/hyperledger/fabric
command: orderer
volumes:
- ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
- ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp:/var/hyperledger/orderer/msp
- ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/:/var/hyperledger/orderer/tls
ports:
- 7050:7050
networks:
- hello

docker-compose-org1-peer0.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

version: '2'

networks:
hello:
services:
peer0.org1.example.com:
container_name: peer0.org1.example.com
image: hyperledger/fabric-peer
environment:
- CORE_PEER_ID=peer0.org1.example.com
- CORE_PEER_LISTENADDRESS=0.0.0.0:7051
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
- CORE_PEER_CHAINCODEADDRESS=peer0.org1.example.com:7052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051
- CORE_PEER_GOSSIP_BOOTSTRAP=peer1.org1.example.com:8051
- CORE_PEER_LOCALMSPID=Org1MSP

- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
# the following setting starts chaincode containers on the same
# bridge network as the peers
# https://docs.docker.com/compose/networking/
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=helloworld_hello
#- CORE_LOGGING_LEVEL=ERROR
- CORE_LOGGING_LEVEL=DEBUG
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_GOSSIP_USELEADERELECTION=true
- CORE_PEER_GOSSIP_ORGLEADER=false
- CORE_PEER_PROFILE_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
- CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: peer node start
volumes:
- /var/run/:/host/var/run/
- ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/fabric/msp
- ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls:/etc/hyperledger/fabric/tls
ports:
- 7051:7051
- 7052:7052
- 7053:7053
# extra_hosts:
# - "orderer.example.com:192.168.235.100"
networks:
- hello

cli_peer0_org1:
container_name: cli_peer0_org1
image: hyperledger/fabric-tools
tty: true
environment:
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_LOGGING_LEVEL=DEBUG
- CORE_PEER_ID=cli_peer0_org1

- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key
- CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
- CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
volumes:
- /var/run/:/host/var/run/
- ./chaincode/go/:/opt/gopath/src/github.com/hyperledger/fabric/helloworld/chaincode/go
- ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
- ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
depends_on:
- peer0.org1.example.com
# extra_hosts:
# - "orderer.example.com:192.168.235.100"
# - "peer0.org1.example.com:192.168.235.101"
# - "peer1.org1.example.com:192.168.235.102"
# - "peer0.org2.example.com:192.168.235.103"
# - "peer1.org2.example.com:192.168.235.104"
networks:
- hello

docker-compose-org1-peer1.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

version: '2'

networks:
hello:
services:
peer1.org1.example.com:
container_name: peer1.org1.example.com
image: hyperledger/fabric-peer
environment:
- CORE_PEER_ID=peer1.org1.example.com
- CORE_PEER_LISTENADDRESS=0.0.0.0:8051
- CORE_PEER_ADDRESS=peer1.org1.example.com:8051
- CORE_PEER_CHAINCODEADDRESS=peer1.org1.example.com:8052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:8052
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org1.example.com:8051
- CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP

- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
# the following setting starts chaincode containers on the same
# bridge network as the peers
# https://docs.docker.com/compose/networking/
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=helloworld_hello
#- CORE_LOGGING_LEVEL=ERROR
- CORE_LOGGING_LEVEL=DEBUG
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_GOSSIP_USELEADERELECTION=true
- CORE_PEER_GOSSIP_ORGLEADER=false
- CORE_PEER_PROFILE_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
- CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: peer node start
volumes:
- /var/run/:/host/var/run/
- ./crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/msp:/etc/hyperledger/fabric/msp
- ./crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls:/etc/hyperledger/fabric/tls
ports:
- 8051:8051
- 8052:8052
- 8053:8053
# extra_hosts:
# - "orderer.example.com:192.168.235.100"
networks:
- hello

cli_peer1_org1:
container_name: cli_peer1_org1
image: hyperledger/fabric-tools
tty: true
environment:
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_LOGGING_LEVEL=DEBUG
- CORE_PEER_ID=cli_peer1_org1
- CORE_PEER_ADDRESS=peer1.org1.example.com:8051
- CORE_PEER_LOCALMSPID=Org1MSP
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/server.key
- CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt
- CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
volumes:
- /var/run/:/host/var/run/
- ./chaincode/go/:/opt/gopath/src/github.com/hyperledger/fabric/helloworld/chaincode/go
- ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
- ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
depends_on:
- peer1.org1.example.com
# extra_hosts:
# - "orderer.example.com:192.168.235.100"
# - "peer1.org1.example.com:192.168.235.101"
# - "peer1.org1.example.com:192.168.235.102"
# - "peer1.org2.example.com:192.168.235.103"
# - "peer1.org2.example.com:192.168.235.104"
networks:
- hello

docker-compose-org2-peer0.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

version: '2'

networks:
hello:
services:
peer0.org2.example.com:
container_name: peer0.org2.example.com
image: hyperledger/fabric-peer
environment:
- CORE_PEER_ID=peer0.org2.example.com
- CORE_PEER_LISTENADDRESS=0.0.0.0:9051
- CORE_PEER_ADDRESS=peer0.org2.example.com:9051
- CORE_PEER_CHAINCODEADDRESS=peer0.org2.example.com:9052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:9052
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org2.example.com:9051
- CORE_PEER_GOSSIP_BOOTSTRAP=peer1.org2.example.com:10051
- CORE_PEER_LOCALMSPID=Org2MSP

- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
# the following setting starts chaincode containers on the same
# bridge network as the peers
# https://docs.docker.com/compose/networking/
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=helloworld_hello
#- CORE_LOGGING_LEVEL=ERROR
- CORE_LOGGING_LEVEL=DEBUG
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_GOSSIP_USELEADERELECTION=true
- CORE_PEER_GOSSIP_ORGLEADER=false
- CORE_PEER_PROFILE_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
- CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: peer node start
volumes:
- /var/run/:/host/var/run/
- ./crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/msp:/etc/hyperledger/fabric/msp
- ./crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls:/etc/hyperledger/fabric/tls
ports:
- 9051:9051
- 9052:9052
- 9053:9053
# extra_hosts:
# - "orderer.example.com:192.168.235.100"
networks:
- hello

cli_peer0_org2:
container_name: cli_peer0_org2
image: hyperledger/fabric-tools
tty: true
environment:
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_LOGGING_LEVEL=DEBUG
- CORE_PEER_ID=cli_peer0_org2
- CORE_PEER_ADDRESS=peer0.org2.example.com:9051
- CORE_PEER_LOCALMSPID=Org2MSP
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/server.key
- CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
- CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
volumes:
- /var/run/:/host/var/run/
- ./chaincode/go/:/opt/gopath/src/github.com/hyperledger/fabric/helloworld/chaincode/go
- ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
- ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
depends_on:
- peer0.org2.example.com
# extra_hosts:
# - "orderer.example.com:192.168.235.100"
# - "peer0.org1.example.com:192.168.235.101"
# - "peer1.org1.example.com:192.168.235.102"
# - "peer0.org2.example.com:192.168.235.103"
# - "peer1.org2.example.com:192.168.235.104"
networks:
- hello

docker-compose-org2-peer1.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

version: '2'

networks:
hello:
services:
peer1.org2.example.com:
container_name: peer1.org2.example.com
image: hyperledger/fabric-peer
environment:
- CORE_PEER_ID=peer1.org2.example.com
- CORE_PEER_LISTENADDRESS=0.0.0.0:10051
- CORE_PEER_ADDRESS=peer1.org2.example.com:10051
- CORE_PEER_CHAINCODEADDRESS=peer1.org2.example.com:10052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:10052
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org2.example.com:10051
- CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org2.example.com:9051
- CORE_PEER_LOCALMSPID=Org2MSP

- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
# the following setting starts chaincode containers on the same
# bridge network as the peers
# https://docs.docker.com/compose/networking/
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=helloworld_hello
#- CORE_LOGGING_LEVEL=ERROR
- CORE_LOGGING_LEVEL=DEBUG
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_GOSSIP_USELEADERELECTION=true
- CORE_PEER_GOSSIP_ORGLEADER=false
- CORE_PEER_PROFILE_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
- CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: peer node start
volumes:
- /var/run/:/host/var/run/
- ./crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/msp:/etc/hyperledger/fabric/msp
- ./crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls:/etc/hyperledger/fabric/tls
ports:
- 10051:10051
- 10052:10052
- 10053:10053
# extra_hosts:
# - "orderer.example.com:192.168.235.100"
networks:
- hello

cli_peer1_org2:
container_name: cli_peer1_org2
image: hyperledger/fabric-tools
tty: true
environment:
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_LOGGING_LEVEL=DEBUG
- CORE_PEER_ID=cli_peer1_org2
- CORE_PEER_ADDRESS=peer1.org2.example.com:10051
- CORE_PEER_LOCALMSPID=Org2MSP
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/server.key
- CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt
- CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
volumes:
- /var/run/:/host/var/run/
- ./chaincode/go/:/opt/gopath/src/github.com/hyperledger/fabric/helloworld/chaincode/go
- ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
- ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
depends_on:
- peer1.org2.example.com
# extra_hosts:
# - "orderer.example.com:192.168.235.100"
# - "peer0.org1.example.com:192.168.235.101"
# - "peer1.org1.example.com:192.168.235.102"
# - "peer0.org2.example.com:192.168.235.103"
# - "peer1.org2.example.com:192.168.235.104"
networks:
- hello

两个CA服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

version: '2'

networks:
hello:

services:
ca0:
image: hyperledger/fabric-ca
environment:
- FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server
- FABRIC_CA_SERVER_CA_NAME=ca-org1
- FABRIC_CA_SERVER_TLS_ENABLED=true
- FABRIC_CA_SERVER_TLS_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.org1.example.com-cert.pem
- FABRIC_CA_SERVER_TLS_KEYFILE=/etc/hyperledger/fabric-ca-server-config/${PRIVATE_KEY1}
- FABRIC_CA_SERVER_PORT=7054
ports:
- "7054:7054"
command: sh -c 'fabric-ca-server start --ca.certfile /etc/hyperledger/fabric-ca-server-config/ca.org1.example.com-cert.pem --ca.keyfile /etc/hyperledger/fabric-ca-server-config/${PRIVATE_KEY1} -b admin:adminpw -d'
volumes:
- ./crypto-config/peerOrganizations/org1.example.com/ca/:/etc/hyperledger/fabric-ca-server-config
- ./client/ca:/root/ca
container_name: ca_peerOrg1
networks:
- hello

ca1:
image: hyperledger/fabric-ca
environment:
- FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server
- FABRIC_CA_SERVER_CA_NAME=ca-org2
- FABRIC_CA_SERVER_TLS_ENABLED=true
- FABRIC_CA_SERVER_TLS_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.org2.example.com-cert.pem
- FABRIC_CA_SERVER_TLS_KEYFILE=/etc/hyperledger/fabric-ca-server-config/${PRIVATE_KEY2}
- FABRIC_CA_SERVER_PORT=9054
ports:
- "9054:9054"
command: sh -c 'fabric-ca-server start --ca.certfile /etc/hyperledger/fabric-ca-server-config/ca.org2.example.com-cert.pem --ca.keyfile /etc/hyperledger/fabric-ca-server-config/${PRIVATE_KEY2} -b admin:adminpw -d'
volumes:
- ./crypto-config/peerOrganizations/org2.example.com/ca/:/etc/hyperledger/fabric-ca-server-config
- ./client/ca:/root/ca
container_name: ca_peerOrg2
networks:
- hello

##4.5 启动docker
执行以下命令启动区块链各个模块。

1
2
3
4
5
docker-compose -f docker-compose-orderer.yaml up -d
docker-compose -f docker-compose-org1-peer0.yaml up -d
docker-compose -f docker-compose-org1-peer1.yaml up -d
docker-compose -f docker-compose-org2-peer0.yaml up -d
docker-compose -f docker-compose-org2-peer1.yaml up -d

两个org的ca服务docker参数配置中分别有:${PRIVATE_KEY1}和${PRIVATE_KEY2}两个变量,具体路径在:
crypto-config/peerOrganizations/org1.example.com/ca/ 下后缀是”_sk”的文件,我们这里写了一个shell脚步用于配置
${PRIVATE_KEY1}和${PRIVATE_KEY2},并启动ca节点。
脚步./startCA.sh文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

COMPOSE_FILE="docker-compose-ca.yaml"
##########
#key1
folder1="crypto-config/peerOrganizations/org1.example.com/ca"
privName1=""
for file_a in ${folder1}/*
do
temp_file=`basename $file_a`

if [ ${temp_file##*.} != "pem" ];then
privName1=$temp_file
fi
done

echo $privName1

############
#key2
folder2="crypto-config/peerOrganizations/org2.example.com/ca"
privName2=""
for file_a in ${folder2}/*
do
temp_file=`basename $file_a`

if [ ${temp_file##*.} != "pem" ];then
privName2=$temp_file
fi
done
echo $privName2


CHANNEL_NAME=$CH_NAME TIMEOUT=$CLI_TIMEOUT PRIVATE_KEY1=$privName1 PRIVATE_KEY2=$privName2 docker-compose -f $COMPOSE_FILE up -d 2>&1

启动CA节点

1
2

./startCA.sh

docker启动后如下所示:
dockerps

5.创建通道并加入通道

  • 节点:peer0.org1.example.com
1
2
3
4
5
6
7
8
9
10
11
12
#1进入peer0 的客户端
docker exec -it cli_peer0_org1 bash
#2设置ca路径
ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

#3创建通道mychannel
peer channel create -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/mychannel.tx --tls --cafile $ORDERER_CA

#4节点加入通道mychannel
peer channel join -b mychannel.block

#5拷贝mychannel.block到宿主机
  • 节点:peer1.org1.example.com
1
2
3
4
5
6
7
8
9
10
11
12

#1拷贝宿主机上的mychannel.block到docker cli_peer1_org1

#2进入peer0 的客户端
docker exec -it cli_peer1_org1 bash

#3设置ca路径
ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem


#4节点加入通道mychannel
peer channel join -b mychannel.block
  • 其他节点与peer1.org1.example.com类似

6.链码开发与安装

6.1 链码开发

在helloworld目录下创建 chaincode/go/helloworld文件夹。

目录fabric-samples/helloworld/chaincode/go/helloworld

我们使用go开发一个包含get和一个set功能的简单的链码,代码如下:

  • chaincode.go
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93

    /*
    *
    * 文件名称 : chaincode.go
    * 创建者 : zgq
    * 创建日期: 2019/11/24
    * 文件描述: 实现存储Helloworld字符串的智能合约
    * 历史记录: 无
    */

    package main

    import (
    "fmt"

    "github.com/hyperledger/fabric/core/chaincode/shim"
    pb "github.com/hyperledger/fabric/protos/peer"
    )

    // SimpleChaincode implements a simple chaincode to manage an asset
    type SimpleChaincode struct {
    }

    // 链码实例化时,调用Init函数初始化数据
    // 链码升级时,也会调用此函数重置或迁移数据
    func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
    // 获取交易提案中的参数
    args := stub.GetStringArgs()
    if len(args) != 2 {
    return shim.Error("Incorrect arguments. Expecting a key and a value")
    }

    // 通过调用stub.PutState()设置变量和数值

    // 在账本上设置key和value
    err := stub.PutState(args[0], []byte(args[1]))
    if err != nil {
    return shim.Error(fmt.Sprintf("Failed to create asset: %s", args[0]))
    }
    return shim.Success(nil)
    }

    // 调用Invoke函数进行资产交易
    // 每笔交易通过get或set操作Init函数创建的key和value
    // 通过set可以创建新的key和value
    func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
    // 获取交易提案中的函数和参数
    fn, args := stub.GetFunctionAndParameters()

    var result string
    var err error
    if fn == "set" {
    result, err = set(stub, args)
    } else { // assume 'get' even if fn is nil
    result, err = get(stub, args)
    }
    if err != nil {
    return shim.Error(err.Error())
    }

    // Return the result as success payload
    return shim.Success([]byte(result))
    }

    // 保存key和value到账本上
    // 如果key存在,覆盖原有的value
    func set(stub shim.ChaincodeStubInterface, args []string) (string, error) {
    if len(args) != 2 {
    return "", fmt.Errorf("Incorrect arguments. Expecting a key and a value")
    }

    err := stub.PutState(args[0], []byte(args[1]))
    if err != nil {
    return "", fmt.Errorf("Failed to set asset: %s", args[0])
    }
    return args[1], nil
    }

    // 获取key对应的value
    func get(stub shim.ChaincodeStubInterface, args []string) (string, error) {
    if len(args) != 1 {
    return "", fmt.Errorf("Incorrect arguments. Expecting a key")
    }

    value, err := stub.GetState(args[0])
    if err != nil {
    return "", fmt.Errorf("Failed to get asset: %s with error: %s", args[0], err)
    }
    if value == nil {
    return "", fmt.Errorf("Asset not found: %s", args[0])
    }
    return string(value), nil
    }

*helloworld.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
*
* 文件名称 : main.go
* 创建者 : zgq
* 创建日期: 2019/11/24
* 文件描述: 主入口函数
* 历史记录: 无
*/

package main

import (
"fmt"

"github.com/hyperledger/fabric/core/chaincode/shim"
)

func main() {
err := shim.Start(new(SimpleChaincode))
if err != nil {
fmt.Printf("Error starting Simple chaincode: %s", err)
}
}

6.2 安装链码

在peer0.org1.example.com 安装链码

1
2
3
4
5
6
7
8
9
10
11
12
13
14

#进入cli_peer0_org1 docker环境
docker exec -it cli_peer0_org1 bash
#orderer证书
ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

#安装链码
peer chaincode install -n mycc -p github.com/hyperledger/fabric/helloworld/chaincode/go/helloworld/ -v 1.0

#查看已经安装的链码
peer chaincode list --installed

#实例化链码,初始化 a=hello
peer chaincode instantiate -o orderer.example.com:7050 --tls --cafile $ORDERER_CA -C mychannel -n mycc -v 1.0 -c '{"Args":["a","hello"]}' -P "OR ('Org1MSP.peer','Org2MSP.peer')"
  • 查询

    1
    peer chaincode query -C mychannel -n mycc -c '{"function":"get","Args":["a"]}'
  • 执行set

    1
    peer chaincode invoke --tls --cafile $ORDERER_CA -C mychannel -n mycc -c '{"function":"set","Args":["a","world"]}'

在peer1.org1.example.com 安装链码

1
2
3
4
5
6
7
8
9
10
11

#进入cli_peer1_org1 docker环境
docker exec -it cli_peer1_org1 bash
#orderer证书
ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

#安装链码
peer chaincode install -n mycc -p github.com/hyperledger/fabric/helloworld/chaincode/go/helloworld/ -v 1.0

#安装完后查询就可以发现数据已经有了
peer chaincode query -C mychannel -n mycc -c '{"function":"get","Args":["a"]}'

在其他节点安装链码

与peer1.org1.example.com 安装链码过程类似。

通过docker ps命令我们会发现多出来几个链码服务,例如:
dev-peer0.org1.example.com-mycc-1.0-388fcb871dc37045ac29faaba82745e39035f4243bf46d1c97df818b4b341bbe
dev-peer1.org1.example.com-mycc-1.0-cd123150154e6bf2df7ce682e0b1bcbea40499416f37a6da3aae14c4eb51b08d
dev-peer0.org2.example.com-mycc-1.0-15b571b3ce849066b7ec74497da3b27e54e0df1345daff3951b94245ce09c42b
dev-peer1.org2.example.com-mycc-1.0-26c2ef32838554aac4f7ad6f100aca865e87959c9a126e86d764c8d01f8346ab